﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace ASCM_MulticopterApp
{
    class ArduinoCommunicator
    {
        SerialPort port;
        //kanali
        int X = 0, Y = 0, Z = 0, T = 0, A = 0, B = 0, C = 0, D = 0, SUM = 0;
        int refreshRate = 44;
        bool _wait = false;
        bool connected = false;
        string comPort = "";


        private static Timer _timer;
        public delegate void On_status_changed(string message, bool status);
        public event On_status_changed status_changed;

        public delegate void RefreshInputRequest(ref int x, ref int y, ref int z);
        public event RefreshInputRequest onRefresh;

        BackgroundWorker backgroundWorker1;

        public void shut()
        {

            _timer.Stop();
            backgroundWorker1.CancelAsync();
            if (port.IsOpen)
                port.Close();
        }
        public bool IsConnected()
        {
            return connected;
        }

        public ArduinoCommunicator()
        {
            port = new SerialPort();
        }

        public bool Connect(string portName, int baudRate)
        {
            if (port.IsOpen)
                port.Close();
        
            port.BaudRate = baudRate;
            port.PortName = portName;

            if (backgroundWorker1 != null && backgroundWorker1.CancellationPending)
                shut();



            try
            {
                port.Open();
                backgroundWorker1 = new BackgroundWorker();
                backgroundWorker1.DoWork += backgroundWorker1_DoWork;
                backgroundWorker1.WorkerReportsProgress = true;
                backgroundWorker1.WorkerSupportsCancellation = true;
                backgroundWorker1.RunWorkerAsync();

                comPort = portName;
                return true;
            }
            catch (Exception ex)
            { 
                status_changed("Cannot connect to Arduino!", false);
                return false;

            }


        }
        public void Disconnect()
        {
            _timer.Stop();
            backgroundWorker1.CancelAsync();
            if (port.IsOpen)
                port.Close();
        }
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            _timer = new System.Timers.Timer(1000 / refreshRate);
            _timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            _timer.Enabled = true;
        }


        public void updatePositions(int x, int y, int z, int t)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
            this.T = t;
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            //počakaj če se prejšnje sporočilo še ni zaključilo
            if (!_wait)
            {

                _wait = true;
                string temp;
                SUM = X + Y + Z;
                //temp = string.Format("X:{0} Y:{1} Z:{2}", X.ToString("000"), Y.ToString("000"), Z.ToString("000"));



                if (SendPositions(string.Format("p{0} {1} {2} {3} {4} ", X.ToString("000"), Y.ToString("000"), Z.ToString("000"), T.ToString("000"), Z.ToString("000"))))
                {
                    _wait = false;
                    connected = true;
                    status_changed("OK", true);
                }
                else
                {
                    status_changed("Serial problem", false);
                    Debug.WriteLine("Arduino serial problem");
                }


                onRefresh(ref X, ref Y, ref Z);
            }
            else
            {
                // _wait = false;
                status_changed("Skipped frame", false);
                Debug.WriteLine("Skipped frame");
            }

        }


        private bool SendPositions(string positions)
        {
            string temp = "";

            try
            {
                if (!port.IsOpen)
                {
                    port.Open();
                }

                port.WriteLine(positions);
                temp = port.ReadLine();

                if (0 == string.Compare(positions, 0, temp, 0, 8))
                {
                    return true;
                }
                else
                    return false;
            }
            catch
            {
                return false;
            }


        }

        public double ScaleRange(double value, double aMin, double aMax, double bMin, double bMax)
        {
            return bMin + (bMax - bMin) * ((value - aMin) / (aMax - aMin));
        }


    }



}
